package ascii;


import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import javafx.util.converter.ByteStringConverter;
import okio.ByteString;

import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.*;

public class Test {
    private static final int LEN_OF_SIGN = 1;
    private static final int NUM_OF_COORDINATE_TYPE = 3;
    private static final int NUM_OF_GETXYP = 10;
    private static byte[] data={11,31,118,24,0,0,4,0,0,0,3,123,6,110,13,100,0,0,61,-48,0,0,-25,-128,0,0,6,-105,48,0,0,0,37,
            -56,0,0,0,9,-47,64,0,0,2,-128,32,18,66,0,-36,-84,1,12,64,0,10,0,0,0,0,0,0,0,-55,96,104,4,40,-16,36,1,-111,-96,0,
            0,5,-68,14,0,66,-112,0,0,1,26,0,0,0,117,0,0,0,14,64,-80,4,0,0,1,0,0,0,0,0,0,0,0,7,16,4,0,29,2,0,38,5,0,49,6,0,55,
            5,0,52,-126,0,62,-119,0,62,-122,0,66,-114,0,65,-118,0,11,3,-72,5,0,0,50,-128,-80,0,2,-88,4,0,0,40,0,80,0,2,96,14,
            -120,16,45,2,59,4,2,-48,57,-57,-96,38,4,112,0,1,-112,77,0,0,8,4,-96,0,7,-123,65,0,-119,45,0,-119,29,0,-123,14,
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    private static int lenOfData=data.length;


    static int XYP_len = 0;
    static int[] rawX = new int[1000000];
    static int[] rawY = new int[1000000];
    static int[] rawPre = new int[1000000];

    private static int a[]=new int[3];

    public static void main(String[] args) {

        //把字节数组放入到字节缓冲区
        ByteBuffer buffer=ByteBuffer.allocate(lenOfData);
        buffer.put(data);
        buffer.flip();

        //缓冲区使用小字节序，因为起始点的获取需要用小字节序
        buffer.order(ByteOrder.LITTLE_ENDIAN);

        //获取起始点坐标，并且取正
        a[0]=buffer.getShort() & 0xFFFF;
        a[1]=buffer.getShort() & 0xFFFF;
        a[2]=buffer.getShort() & 0xFFFF;
        System.out.println("startX " + a[0] + ", startY " + a[1] + ", startP " + a[2]);


        Observable<NotePenPointer> vectors = Observable.empty();

        while(buffer.hasRemaining()){
            //字节强转为int时，会自动在高位补符号位的值，如果是负数则高位全是1，所以要与一下0xFF
            int lenOfUnit = buffer.get() & 0xFF;
            int numOfBit = (lenOfUnit + LEN_OF_SIGN) * NUM_OF_COORDINATE_TYPE * NUM_OF_GETXYP;
            int numOfByte = numOfBit / Byte.SIZE + (numOfBit % Byte.SIZE == 0 ? 0 : 1);

            byte[] tmpBuffer=new byte[numOfByte];
            buffer.get(tmpBuffer);

            vectors=vectors.concatWith(parseVectors(tmpBuffer,lenOfUnit+LEN_OF_SIGN));
            vectors.subscribe(new Consumer<NotePenPointer>() {
                @Override
                public void accept(NotePenPointer notePenPointer) throws Exception {
                    System.out.println("notePenPointerVector " + notePenPointer);
                }
            });
        }

//        vectors.blockingSubscribe(new Consumer<NotePenPointerVector>() {
//            @Override
//            public void accept(NotePenPointerVector notePenPointerVector) throws Exception {
//                list.add(notePenPointerVector);
//            }
//        }, new Consumer<Throwable>() {
//            @Override
//            public void accept(Throwable throwable) throws Exception {
//                throwable.printStackTrace();
//            }
//        }, new Action() {
//            @Override
//            public void run() throws Exception {
//                for (NotePenPointerVector v: list) {
//                    System.out.println("x:"+v.vectorX+" y:"+v.vectorX+" p:"+v.vectorX);
//                }
//            }
//        });

        vectors.subscribe(new Consumer<NotePenPointer>() {
            @Override
            public void accept(NotePenPointer notePenPointer) throws Exception {
                System.out.println("notePenPointerVector " + notePenPointer);
            }
        });
    }

    private static Observable<NotePenPointer> parseVectors(byte[] tmpBuffer, int lenOfUnit) {

        return Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> e) throws Exception {
                for (int i = 0; i < tmpBuffer.length; i++) {
                    for (int bitIndex = Byte.SIZE-1; bitIndex >= 0; bitIndex--) {
                        int val=(tmpBuffer[i] & (1 << bitIndex)) == 0 ? 0 : 1;
                        e.onNext(val);
                    }
                }
            }
        }).doOnNext(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
//                System.out.println("a " + integer);
            }
        }).buffer(lenOfUnit).map(new Function<List<Integer>, Integer>() {
            @Override
            public Integer apply(List<Integer> bits) throws Exception {
                boolean sign = bits.get(0) == 0;

                int ret=0;
                for (int i = 1; i < bits.size(); i++) {
                    ret = (ret << 1) + bits.get(i);
                }
                int res = ret * (sign ? 1 : -1);
//                System.out.println("res " + res);
                return res;
            }
        }).doOnNext(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
//                System.out.println("bbb "+integer);
            }
        }).buffer(3).map(new Function<List<Integer>, NotePenPointer>() {
            @Override
            public NotePenPointer apply(List<Integer> integers) throws Exception {
                a[0]+=integers.get(0);
                a[1]+=integers.get(1);
                a[2]+=integers.get(2);

                for(int j = 0; j < 3; ++j) {
                    char low = (char)(a[j] & 255);
                    char high = (char)(a[j] >> 8 & 255);

                    if(j == 0) {
                        rawX[XYP_len] = low + (high << 8);
                    }

                    if(j == 1) {
                        rawY[XYP_len] = low + (high << 8);
                    }

                    if(j == 2) {
                        rawPre[XYP_len] = low + (high << 8);
                    }
                }
                XYP_len++;

                return new NotePenPointer(rawX[XYP_len],rawY[XYP_len],rawPre[XYP_len]);
            }
        });
    }


    public static class NotePenPointer {
        public int x;
        public int y;
        public int p;

        public NotePenPointer(Integer x, Integer y, Integer p) {
            this.x = x;
            this.y = y;
            this.p = p;
        }

        @Override
        public String toString() {
            return "NotePenPointer{" +
                    "x=" + x +
                    ", y=" + y +
                    ", p=" + p +
                    '}';
        }
    }


}
